#pragma once
#include <algorithm>
#include <chrono>
#include <cstdarg>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <map>
#include <mutex>
#include <sstream>
#include <string>
#include <thread>
#include <vector>

namespace toolsLib
{

class Logger
{
  public:
    static Logger& getInstance();

    void log(const std::string& file,
             const std::string& funcName,
             const int& line,
             const int& level,
             const std::string& message);

    void log(const std::string& file,
             const std::string& funcName,
             const int& line,
             const int& level,
             const int& message);

    void log(const std::string& file,
             const std::string& funcName,
             const int& line,
             const int& level,
             const std::ostringstream& message);

    void log(const std::string& file,
             const std::string& funcName,
             const int& line,
             const int& level,
             const char* str,
             ...);

    void log(const std::string& file,
             const std::string& funcName,
             const int& line,
             const char* str,
             ...);

    void logOnce(const std::string& file,
                 const std::string& funcName,
                 const int& line,
                 const int& level,
                 const std::string& message);

    void logOnce(const std::string& file,
                 const std::string& funcName,
                 const int& line,
                 const int& level,
                 const int& message);

    void logOnce(const std::string& file,
                 const std::string& funcName,
                 const int& line,
                 const int& level,
                 const std::ostringstream& message);

    void logOnce(const std::string& file,
                 const std::string& funcName,
                 const int& line,
                 const int& level,
                 const char* str,
                 ...);

    void logOnce(const std::string& file,
                 const std::string& funcName,
                 const int& line,
                 const char* str,
                 ...);

    void logCtrlHz(const std::string& file,
                   const std::string& funcName,
                   const int& line,
                   const int& level,
                   const int& hz,
                   const std::string& message);

    void logCtrlHz(const std::string& file,
                   const std::string& funcName,
                   const int& line,
                   const int& level,
                   const int& hz,
                   const int& message);

    void logCtrlHz(const std::string& file,
                   const std::string& funcName,
                   const int& line,
                   const int& level,
                   const int& hz,
                   const std::ostringstream& message);

    void logCtrlHz(const std::string& file,
                   const std::string& funcName,
                   const int& line,
                   const int& level,
                   const int& hz,
                   const char* str,
                   ...);

    void logCtrlHz(const std::string& file,
                   const std::string& funcName,
                   const int& line,
                   const int& hz,
                   const char* str,
                   ...);

    template <typename T>
    void templateLog(const std::string& file,
                     const std::string& funcName,
                     const int& line,
                     const int& level,
                     const T& message);

    template <typename T>
    void templatelogOnce(const std::string& file,
                         const std::string& funcName,
                         const int& line,
                         const int& level,
                         const T& message);

    template <typename T>
    void templatelogCtrlHz(const std::string& file,
                           const std::string& funcName,
                           const int& line,
                           const int& level,
                           const int& hz,
                           const T& message);

    std::string getFileName(const std::string& path);

    void timeCurrently(std::string& time);

    void timeCurrently(int64_t& time);

    std::string formatFont(const std::string& message,
                           const int display,
                           const int fontcolor,
                           const int backgroud);

    void setLogPath(std::string& path);

    void setLogPath(const char* path);

    void setPureLog(const bool pure);

    void setSaveLog(const bool save);

    // 日志分割功能
    void setLogSplit(bool enable);
    void setLogSplitByTime(int64_t durationMs);  // 设置按时间分割（毫秒）
    void setLogAutoCompress(bool enable);        // 设置分割后是否自动压缩
    void splitLog();                             // 手动触发分割

    void unpolishedLog(int level, std::string& log1, std::string& log2, std::string& log3);

    void unpolishedLog(int level, std::string& log);

    template <typename T>
    std::string to_string(const T& message);

    std::string to_string(const int& message);

    std::string to_string(const std::string& message);

    std::string to_string(const std::ostringstream& message);

  private:
    Logger();

    ~Logger();

    Logger(const Logger&) = delete;

    Logger& operator=(const Logger&) = delete;

    std::string color(int display, int fontcolor, int backgroud);

    bool timeBuilder(const std::string& funcName, const int& line, const int& timeGap);

    bool timer(const std::string& funcName, const int& line, const int& timeGap);

    std::ofstream logFile;

    std::string oldPath;

    bool saveLog;

    bool pureLog;

    bool setPath;

    // 日志分割相关
    bool enableLogSplit;                    // 是否启用日志分割
    int64_t splitDurationMs;                // 按时间分割的时长（毫秒），0表示禁用时间分割
    std::chrono::time_point<std::chrono::system_clock> logFileStartTime;  // 当前日志文件开始时间
    bool autoCompress;                      // 分割后是否自动压缩
    std::string baseLogPath;                // 基础日志路径（不含时间戳）

    std::mutex logMutex;

    std::mutex saveLogMutex;

    // 内部方法
    void checkAndSplitLog();                // 检查是否需要分割日志
    std::string generateLogFileName(const std::string& basePath);  // 生成带时间戳的日志文件名
    void compressLogFile(const std::string& filePath);  // 压缩日志文件
};

}  // namespace toolsLib
